/*
 * @Descripttion: 多画面播放器类
 * @version: V1.0.0.0
 * @Author: zhaozhenzhuo
 * @Date: 2025-01-10 13:18:17
 * @LastEditors: zhaozhenzhuo
 * @LastEditTime: 2025-02-17 18:26:08
 */
import Player, { Events } from 'xgplayer';
import FlvPlugin from 'xgplayer-flv';
import HlsPlugin from 'xgplayer-hls';
import 'xgplayer/dist/index.min.css';
import { v4 as uuidv4 } from 'uuid';
import {
	MultiPlayerOptionsRequireOne,
	MultiPlayerClassOptions,
	PlayerSizeObj,
	PlayerOptions,
	UrlListOptionsRequireOne,
	PlayerListOptions
} from './types';
import { validateParams, hasDomByCSSSelector, createDom, setDOMStyle, setWaterMark } from './utils';
import { APIMixin } from './APIMixin';
import { FunctionMixin } from './FunctionMixin';
import { CLASS_CONFIG, DEFAULT_CONFIG } from './config';

class MultiPlayer {
	private type: MultiPlayerClassOptions['type']; // 播放器类型
	private el: MultiPlayerClassOptions['el']; // 容器DOM
	private urlList: MultiPlayerClassOptions['urlList']; // 视频源列表
	private isLive: MultiPlayerClassOptions['isLive']; // 是否为直播
	private containerWidth: MultiPlayerClassOptions['width']; // 容器宽度
	private containerHeight: MultiPlayerClassOptions['height']; // 容器高度
	private maxContainerWidth: MultiPlayerClassOptions['maxWidth']; // 最大容器宽度
	private maxContainerHeight: MultiPlayerClassOptions['maxHeight']; // 最大容器高度
	private verticalAlign: MultiPlayerClassOptions['verticalAlign']; // 垂直对齐方式
	private horizontalAlign: MultiPlayerClassOptions['horizontalAlign']; // 水平对齐方式
	private gap: MultiPlayerClassOptions['gap']; // 画面间隔
	private borderStyle: MultiPlayerClassOptions['borderStyle']; // 边框样式
	private autoplay: MultiPlayerClassOptions['autoplay']; // 自动播放
	private displayMode: MultiPlayerClassOptions['displayMode']; // 显示模式
	private showType: MultiPlayerClassOptions['showType']; // 显示类型
	private classList: MultiPlayerClassOptions['classList']; // 类名列表
	private playerList: MultiPlayerClassOptions['playerList']; // 播放器列表
	private isFullscreen: MultiPlayerClassOptions['isFullscreen']; // 是否全屏
	private currentTime: MultiPlayerClassOptions['currentTime']; // 初始播放时间
	private enableVolumeMemory: MultiPlayerClassOptions['enableVolumeMemory']; // 启用音量记忆
	private endTips: MultiPlayerClassOptions['endTips']; // 结束提示
	private hasVol: MultiPlayerClassOptions['hasVol']; // 是否有声音
	private progressDot: MultiPlayerClassOptions['progressDot']; // 进度点
	private watermarkText: MultiPlayerClassOptions['watermarkText']; // 水印文本
	private commonStyle: MultiPlayerClassOptions['commonStyle']; // 公共样式
	private isFirst: boolean; // 是否是初次渲染播放器
	private seekingCallback: MultiPlayerClassOptions['seekingCallback']; // 切换画面后的回调
	private preloadTime: MultiPlayerClassOptions['preloadTime']; // 预加载时间

	constructor(options: MultiPlayerOptionsRequireOne) {
		// 验证参数
		validateParams(options);

		this.type = options.type; // 播放器类型，flv,hls,mp4
		this.el = options.id // 容器DOM
			? (document.querySelector(`#${options.id}`) as HTMLElement)
			: (options.el as HTMLElement);
		this.urlList = JSON.parse(JSON.stringify(options.urlList)).slice(0, 6); // 视频源列表
		// 筛选urlList中不存在id或url的项，如果出现多个hasVol为true的项，只保留第一个满足条件的项
		let _existHasVol = false;
		this.urlList.forEach((item: UrlListOptionsRequireOne) => {
			if (!item.url) {
				// 如果没有url，则显示“暂无画面”
				item.placeholder = DEFAULT_CONFIG.placeholder;
			}
			// 如果没有id，则生成一个id
			if (!item.id) {
				item.id = uuidv4();
			}
			if (_existHasVol && item.hasVol) {
				item.hasVol = false;
			} else if (item.hasVol) {
				_existHasVol = true;
			}
		});

		this.isLive = options.isLive ?? DEFAULT_CONFIG.isLive; // 是否为直播
		this.containerWidth = options.width; // 容器宽度
		this.containerHeight = options.height; // 容器高度
		this.maxContainerWidth = options.maxWidth; // 最大容器宽度
		this.maxContainerHeight = options.maxHeight; // 最大容器高度
		this.verticalAlign = options.verticalAlign ?? DEFAULT_CONFIG.verticalAlign; // 垂直对齐方式 top,center,bottom
		this.horizontalAlign = options.horizontalAlign ?? DEFAULT_CONFIG.horizontalAlign; // 水平对齐方式 left,center,right
		this.gap = options.gap ?? DEFAULT_CONFIG.gap; // 画面间隔
		this.borderStyle = options.borderStyle; // 边框样式
		this.autoplay = options.autoplay ?? DEFAULT_CONFIG.autoplay; // 是否自动播放
		this.displayMode = DEFAULT_CONFIG.displayMode; // 显示模式 pave,pic_in_pic
		this.showType = DEFAULT_CONFIG.showType; // 显示类型 width,height
		this.classList = [
			// 类名列表，存储多画面中每个画面的信息 className类名 usedId使用该类名的画面id，isLarge该类名是否是主画面
			{ className: CLASS_CONFIG.LARGE_CLASS, usedId: '', isLarge: true },
			{ className: CLASS_CONFIG.SMALL_CLASS_1, usedId: '', isLarge: false },
			{ className: CLASS_CONFIG.SMALL_CLASS_2, usedId: '', isLarge: false },
			{ className: CLASS_CONFIG.SMALL_CLASS_3, usedId: '', isLarge: false },
			{ className: CLASS_CONFIG.SMALL_CLASS_4, usedId: '', isLarge: false },
			{ className: CLASS_CONFIG.SMALL_CLASS_5, usedId: '', isLarge: false }
		];
		// 播放器列表，在urlList的基础上添加了属性 player播放器对象 isLarge是否是主画面 timer单击画面定时器 root播放器容器dom（video-wrap容器）
		this.playerList = JSON.parse(JSON.stringify(this.urlList));
		this.isFullscreen = false; // 是否全屏
		this.currentTime = options.currentTime; // 初始播放时间
		this.enableVolumeMemory = options.enableVolumeMemory ?? DEFAULT_CONFIG.enableVolumeMemory; // 启用音量记忆
		this.endTips = options.endTips ?? DEFAULT_CONFIG.endTips; // 结束提示
		// 根据urlList中是否有存在hasVol属性的项判断是否采用特定视角有声音的策略
		this.hasVol = this.urlList.findIndex((item) => item.hasVol) !== -1;
		this.progressDot = options.progressDot ?? DEFAULT_CONFIG.progressDot; // 进度点
		this.watermarkText = options.watermarkText ?? DEFAULT_CONFIG.watermarkText; // 水印文本
		this.commonStyle = options.commonStyle ?? {}; // 公共样式，一些关键点颜色配置
		this.isFirst = true; // 是否是初次渲染播放器，控制autoplay属性是否生效
		this.seekingCallback = options.seekingCallback;
		this.preloadTime = options.preloadTime ?? undefined; // 预加载时间，undefined表示不预加载

		// 初始化多画面播放器
		this.init();
	}

	// 初始化多画面播放器
	private init(): void {
		// 初始化尺寸
		this.initSize();
		// 创建DOM
		this.initDOM();
	}

	// 初始化尺寸
	private initSize(width?: number, height?: number): void {
		if (width && height) {
			this.containerWidth = width;
			this.containerHeight = height;
		}
		// 计算容器尺寸
		this.initContaierSize();
		// 计算播放器尺寸
		const _obj = this.initPlayerSize();
		// 初始化样式
		this.initStyle(_obj);
	}

	// 计算容器尺寸
	private initContaierSize(): void {
		if (this.displayMode === 'pave') {
			if (this.containerWidth && !this.containerHeight) {
				// 仅提供宽度，计算高度
				if (this.urlList.length === 1) {
					// 单画面，根据宽度计算高度
					this.containerHeight = (this.containerWidth * 9) / 16;
				} else if (this.urlList.length === 2 || this.urlList.length === 3) {
					// 2或3画面，根据宽度计算高度
					this.containerHeight = (9 * this.containerWidth - this.gap) / 24;
				} else if (this.urlList.length === 4) {
					// 4画面，根据宽度计算高度
					this.containerHeight = (9 * this.containerWidth + 7 * this.gap) / 16;
				} else if (this.urlList.length === 5) {
					// 5画面，根据宽度计算高度
					this.containerHeight = (27 * this.containerWidth + 29 * this.gap) / 40;
				} else {
					// 6画面，根据宽度计算高度
					this.containerHeight = (3 * this.containerWidth + 2 * this.gap) / 8;
				}
				// 如果提供了最大高度且计算高度大于最大高度，使用最大高度
				if (this.maxContainerHeight && this.containerHeight > this.maxContainerHeight) {
					this.containerHeight = this.maxContainerHeight;
					this.showType = 'height';
				} else {
					this.showType = 'width';
				}
			} else if (!this.containerWidth && this.containerHeight) {
				// 仅提供高度，计算宽度
				if (this.urlList.length === 1) {
					// 单画面，根据高度计算宽度
					this.containerWidth = (this.containerHeight * 16) / 9;
				} else if (this.urlList.length === 2 || this.urlList.length === 3) {
					// 2或3画面，根据高度计算宽度
					this.containerWidth = (8 / 3) * this.containerHeight + (1 / 9) * this.gap;
				} else if (this.urlList.length === 4) {
					// 4画面，根据高度计算宽度
					this.containerWidth = (16 * this.containerHeight - 7 * this.gap) / 9;
				} else if (this.urlList.length === 5) {
					// 5画面，根据高度计算宽度
					this.containerWidth = (40 * this.containerHeight - 29 * this.gap) / 27;
				} else {
					// 6画面，根据高度计算宽度
					this.containerWidth = (8 * this.containerHeight - 2 * this.gap) / 3;
				}
				// 如果提供了最大宽度且计算宽度大于最大宽度，使用最大宽度
				if (this.maxContainerWidth && this.containerWidth > this.maxContainerWidth) {
					this.containerWidth = this.maxContainerWidth;
					this.showType = 'width';
				} else {
					this.showType = 'height';
				}
			} else if (this.containerWidth && this.containerHeight) {
				// 同时提供宽度和高度，计算出以宽度还是高度为准
				let _containerHeight;
				if (this.urlList.length === 1) {
					// 单画面，根据宽度计算高度
					_containerHeight = (this.containerWidth * 9) / 16;
				} else if (this.urlList.length === 2 || this.urlList.length === 3) {
					// 2或3画面，根据宽度计算高度
					_containerHeight = (9 * this.containerWidth - this.gap) / 24;
				} else if (this.urlList.length === 4) {
					// 4画面，根据宽度计算高度
					_containerHeight = (9 * this.containerWidth + 7 * this.gap) / 16;
				} else if (this.urlList.length === 5) {
					// 5画面，根据宽度计算高度
					_containerHeight = (27 * this.containerWidth + 29 * this.gap) / 40;
				} else {
					// 6画面，根据宽度计算高度
					_containerHeight = (3 * this.containerWidth + 2 * this.gap) / 8;
				}
				if (_containerHeight > this.containerHeight) {
					this.showType = 'height';
				} else {
					this.showType = 'width';
				}
			}
		}
	}

	// 计算播放器尺寸
	private initPlayerSize(): PlayerSizeObj {
		const _obj: PlayerSizeObj = {
			largeTop: 0,
			largeLeft: 0,
			largeWidth: 0,
			largeHeight: 0,
			small1Top: 0,
			small1Right: 0,
			small1Width: 0,
			small1Height: 0,
			small2Bottom: 0,
			small2Right: 0,
			small2Width: 0,
			small2Height: 0,
			small3Bottom: 0,
			small3Right: 0,
			small3Width: 0,
			small3Height: 0,
			small4Bottom: 0,
			small4Right: 0,
			small4Width: 0,
			small4Height: 0,
			small5Bottom: 0,
			small5Right: 0,
			small5Width: 0,
			small5Height: 0
		};
		if (this.displayMode === 'pave') {
			let _containerWidth = 0;
			let _containerHeight = 0;
			if (!this.isFullscreen) {
				// 非全屏
				_containerWidth = this.containerWidth as number;
				_containerHeight = this.containerHeight as number;
			} else {
				// 全屏
				_containerWidth = window.screen.width / window.devicePixelRatio;
				_containerHeight = window.screen.height / window.devicePixelRatio;
			}

			if (this.urlList.length === 1) {
				// 1画面
				if (this.showType === 'height') {
					// 以高度为准
					_obj.largeWidth = (_containerHeight * 16) / 9;
					_obj.largeHeight = _containerHeight;
					_obj.largeTop = 0;
					if (!this.horizontalAlign || this.horizontalAlign === 'center') {
						// 居中对齐
						_obj.largeLeft = (_containerWidth - _obj.largeWidth) / 2;
					} else if (this.horizontalAlign === 'left') {
						// 左对齐
						_obj.largeLeft = 0;
					} else {
						// 右对齐
						_obj.largeLeft = _containerWidth - _obj.largeWidth;
					}
				} else {
					// 以宽度为准
					_obj.largeWidth = _containerWidth;
					_obj.largeHeight = (_containerWidth * 9) / 16;
					_obj.largeLeft = 0;
					if (!this.verticalAlign || this.verticalAlign === 'center') {
						// 居中对齐
						_obj.largeTop = (_containerHeight - _obj.largeHeight) / 2;
					} else if (this.verticalAlign === 'top') {
						// 顶部对齐
						_obj.largeTop = 0;
					} else {
						// 底部对齐
						_obj.largeTop = _containerHeight - _obj.largeHeight;
					}
				}
			} else if (this.urlList.length === 2 || this.urlList.length === 3) {
				// 2 3画面
				if (this.showType === 'height') {
					// 以高度为准
					_obj.largeWidth = (_containerHeight * 16) / 9;
					_obj.largeHeight = _containerHeight;
					_obj.largeTop = 0;
					const _offset =
						(_containerWidth -
							(((_containerHeight - this.gap) / 2) * 16) / 9 -
							_obj.largeWidth -
							this.gap) /
						2;

					_obj.small1Height = (_containerHeight - 2) / 2;
					_obj.small1Width = (_obj.small1Height * 16) / 9;
					_obj.small1Top = 0;

					_obj.small2Height = (_containerHeight - 2) / 2;
					_obj.small2Width = (_obj.small2Height * 16) / 9;
					_obj.small2Bottom = 0;

					if (!this.horizontalAlign || this.horizontalAlign === 'center') {
						// 居中对齐
						_obj.largeLeft = _offset;
						_obj.small1Right = _offset;
						_obj.small2Right = _offset;
					} else if (this.horizontalAlign === 'left') {
						// 左对齐
						_obj.largeLeft = 0;
						_obj.small1Right = _offset * 2;
						_obj.small2Right = _offset * 2;
					} else {
						// 右对齐
						_obj.largeLeft = _offset * 2;
						_obj.small1Right = 0;
						_obj.small2Right = 0;
					}
				} else {
					// 以宽度为准
					_obj.small1Height = (9 * _containerWidth - 25 * this.gap) / 48;
					_obj.small1Width = (_obj.small1Height * 16) / 9;
					const _offset = (_containerHeight - 2 * _obj.small1Height - this.gap) / 2;
					_obj.small1Right = 0;

					_obj.small2Height = (9 * _containerWidth - 25 * this.gap) / 48;
					_obj.small2Width = (_obj.small2Height * 16) / 9;
					_obj.small2Right = 0;

					_obj.largeHeight = 2 * _obj.small1Height + 2;
					_obj.largeWidth = (_obj.largeHeight * 16) / 9;
					_obj.largeLeft = 0;

					if (!this.verticalAlign || this.verticalAlign === 'center') {
						// 居中对齐
						_obj.small1Top = _offset;
						_obj.small2Bottom = _offset;
						_obj.largeTop = _offset;
					} else if (this.verticalAlign === 'top') {
						// 顶部对齐
						_obj.small1Top = 0;
						_obj.small2Bottom = _offset * 2;
						_obj.largeTop = 0;
					} else {
						// 底部对齐
						_obj.small1Top = _offset * 2;
						_obj.small2Bottom = 0;
						_obj.largeTop = _offset * 2;
					}
				}
			} else if (this.urlList.length === 4) {
				// 4画面
				if (this.showType === 'height') {
					// 以高度为准
					_obj.largeHeight = (_containerHeight - this.gap) / 2;
					_obj.largeWidth = (_obj.largeHeight * 16) / 9;
					_obj.largeTop = 0;
					const _offset = (_containerWidth - this.gap - _obj.largeWidth * 2) / 2;

					_obj.small1Height = _obj.largeHeight;
					_obj.small1Width = _obj.largeWidth;
					_obj.small1Top = _obj.largeHeight + this.gap;

					_obj.small2Height = _obj.largeHeight;
					_obj.small2Width = _obj.largeWidth;
					_obj.small2Bottom = _obj.largeHeight + this.gap;

					_obj.small3Height = _obj.largeHeight;
					_obj.small3Width = _obj.largeWidth;
					_obj.small3Bottom = 0;

					if (!this.horizontalAlign || this.horizontalAlign === 'center') {
						// 居中对齐
						_obj.largeLeft = _offset;
						_obj.small1Right = _offset + _obj.largeWidth + this.gap;
						_obj.small2Right = _offset;
						_obj.small3Right = _offset;
					} else if (this.horizontalAlign === 'left') {
						// 左对齐
						_obj.largeLeft = 0;
						_obj.small1Right = _offset * 2 + _obj.largeWidth + this.gap;
						_obj.small2Right = _offset * 2;
						_obj.small3Right = _offset * 2;
					} else {
						// 右对齐
						_obj.largeLeft = _offset * 2;
						_obj.small1Right = _obj.largeWidth + this.gap;
						_obj.small2Right = 0;
						_obj.small3Right = 0;
					}
				} else {
					// 以宽度为准
					_obj.largeWidth = (_containerWidth - this.gap) / 2;
					_obj.largeHeight = (_obj.largeWidth * 9) / 16;
					_obj.largeLeft = 0;
					const _offset = (_containerHeight - 2 * _obj.largeHeight - this.gap) / 2;

					_obj.small1Height = _obj.largeHeight;
					_obj.small1Width = _obj.largeWidth;
					_obj.small1Right = _obj.largeWidth + this.gap;

					_obj.small2Height = _obj.largeHeight;
					_obj.small2Width = _obj.largeWidth;
					_obj.small2Right = 0;

					_obj.small3Height = _obj.largeHeight;
					_obj.small3Width = _obj.largeWidth;
					_obj.small3Right = 0;

					if (!this.verticalAlign || this.verticalAlign === 'center') {
						// 居中对齐
						_obj.largeTop = _offset;
						_obj.small1Top = _offset + _obj.largeHeight + this.gap;
						_obj.small2Bottom = _offset + _obj.largeHeight + this.gap;
						_obj.small3Bottom = _offset;
					} else if (this.verticalAlign === 'top') {
						// 顶部对齐
						_obj.largeTop = 0;
						_obj.small1Top = _obj.largeHeight + this.gap;
						_obj.small2Bottom = _offset * 2 + _obj.largeHeight + this.gap;
						_obj.small3Bottom = _offset * 2;
					} else {
						// 底部对齐
						_obj.largeTop = _offset * 2;
						_obj.small1Top = _offset * 2 + _obj.largeHeight + this.gap;
						_obj.small2Bottom = _obj.largeHeight + this.gap;
						_obj.small3Bottom = 0;
					}
				}
			} else if (this.urlList.length === 5) {
				// 5画面
				if (this.showType === 'height') {
					// 以高度为准
					_obj.largeHeight = (_containerHeight - this.gap) / 2;
					_obj.largeWidth = (_obj.largeHeight * 16) / 9;
					_obj.largeTop = 0;

					_obj.small1Height = _obj.largeHeight;
					_obj.small1Width = _obj.largeWidth;
					_obj.small1Top = _obj.largeHeight + this.gap;

					_obj.small2Height = (_containerHeight - 2 * this.gap) / 3;
					_obj.small2Width = (_obj.small2Height * 16) / 9;
					_obj.small2Bottom = 2 * _obj.small2Height + 2 * this.gap;

					_obj.small3Height = _obj.small2Height;
					_obj.small3Width = _obj.small2Width;
					_obj.small3Bottom = _obj.small2Height + this.gap;

					_obj.small4Height = _obj.small2Height;
					_obj.small4Width = _obj.small2Width;
					_obj.small4Bottom = 0;

					const _offset = (_containerWidth - this.gap - _obj.largeWidth - _obj.small2Width) / 2;

					if (!this.horizontalAlign || this.horizontalAlign === 'center') {
						// 居中对齐
						_obj.largeLeft = _offset;
						_obj.small1Right = _offset + _obj.small2Width + this.gap;
						_obj.small2Right = _offset;
						_obj.small3Right = _offset;
						_obj.small4Right = _offset;
					} else if (this.horizontalAlign === 'left') {
						// 左对齐
						_obj.largeLeft = 0;
						_obj.small1Right = _offset * 2 + _obj.small2Width + this.gap;
						_obj.small2Right = _offset * 2;
						_obj.small3Right = _offset * 2;
						_obj.small4Right = _offset * 2;
					} else {
						// 右对齐
						_obj.largeLeft = _offset * 2;
						_obj.small1Right = _obj.largeWidth + this.gap;
						_obj.small2Right = 0;
						_obj.small3Right = 0;
						_obj.small4Right = 0;
					}
				} else {
					// 以宽度为准
					_obj.largeHeight = (27 * _containerWidth - 11 * this.gap) / 80;
					_obj.largeWidth = (_obj.largeHeight * 16) / 9;
					_obj.largeLeft = 0;
					const _offset = (_containerHeight - 2 * _obj.largeHeight - this.gap) / 2;

					_obj.small2Height = (9 * _containerWidth - 17 * this.gap) / 40;
					_obj.small2Width = (_obj.small2Height * 16) / 9;
					_obj.small2Right = 0;

					_obj.small3Height = _obj.small2Height;
					_obj.small3Width = _obj.small2Width;
					_obj.small3Right = 0;

					_obj.small4Height = _obj.small2Height;
					_obj.small4Width = _obj.small2Width;
					_obj.small4Right = 0;

					_obj.small1Height = _obj.largeHeight;
					_obj.small1Width = _obj.largeWidth;
					_obj.small1Right = _obj.small2Width + this.gap;

					if (!this.verticalAlign || this.verticalAlign === 'center') {
						// 居中对齐
						_obj.largeTop = _offset;
						_obj.small1Top = _offset + _obj.largeHeight + this.gap;
						_obj.small2Bottom = _offset + _obj.small2Height * 2 + this.gap * 2;
						_obj.small3Bottom = _offset + _obj.small2Height + this.gap;
						_obj.small4Bottom = _offset;
					} else if (this.verticalAlign === 'top') {
						// 顶部对齐
						_obj.largeTop = 0;
						_obj.small1Top = _obj.largeHeight + this.gap;
						_obj.small2Bottom = _offset * 2 + _obj.small2Height * 2 + this.gap * 2;
						_obj.small3Bottom = _offset * 2 + _obj.small2Height + this.gap;
						_obj.small3Bottom = _offset * 2;
					} else {
						// 底部对齐
						_obj.largeTop = _offset * 2;
						_obj.small1Top = _offset * 2 + _obj.largeHeight + this.gap;
						_obj.small2Bottom = _obj.small2Height * 2 + this.gap * 2;
						_obj.small3Bottom = _obj.small2Height + this.gap;
						_obj.small3Bottom = 0;
					}
				}
			} else {
				// 6画面
				if (this.showType === 'height') {
					// 以高度为准
					_obj.largeHeight = (_containerHeight - this.gap) / 2;
					_obj.largeWidth = (_obj.largeHeight * 16) / 9;
					_obj.largeTop = 0;
					const _offset = (_containerWidth - this.gap * 2 - _obj.largeWidth * 3) / 2;

					_obj.small1Height = _obj.largeHeight;
					_obj.small1Width = _obj.largeWidth;
					_obj.small1Top = _obj.largeHeight + this.gap;

					_obj.small2Height = _obj.largeHeight;
					_obj.small2Width = _obj.largeWidth;
					_obj.small2Bottom = _obj.largeHeight + this.gap;

					_obj.small3Height = _obj.largeHeight;
					_obj.small3Width = _obj.largeWidth;
					_obj.small3Bottom = 0;

					_obj.small4Height = _obj.largeHeight;
					_obj.small4Width = _obj.largeWidth;
					_obj.small4Bottom = _obj.largeHeight + this.gap;

					_obj.small5Height = _obj.largeHeight;
					_obj.small5Width = _obj.largeWidth;
					_obj.small5Bottom = 0;

					if (!this.horizontalAlign || this.horizontalAlign === 'center') {
						// 居中对齐
						_obj.largeLeft = _offset;
						_obj.small1Right = _offset + _obj.largeWidth * 2 + this.gap * 2;
						_obj.small2Right = _offset + _obj.largeWidth + this.gap;
						_obj.small3Right = _offset + _obj.largeWidth + this.gap;
						_obj.small4Right = _offset;
						_obj.small5Right = _offset;
					} else if (this.horizontalAlign === 'left') {
						// 左对齐
						_obj.largeLeft = 0;
						_obj.small1Right = _offset * 2 + _obj.largeWidth * 2 + this.gap * 2;
						_obj.small2Right = _offset * 2 + _obj.largeWidth + this.gap;
						_obj.small3Right = _offset * 2 + _obj.largeWidth + this.gap;
						_obj.small4Right = _offset * 2;
						_obj.small5Right = _offset * 2;
					} else {
						// 右对齐
						_obj.largeLeft = _offset * 2;
						_obj.small1Right = _obj.largeWidth * 2 + this.gap * 2;
						_obj.small2Right = _obj.largeWidth + this.gap;
						_obj.small3Right = _obj.largeWidth + this.gap;
						_obj.small3Right = 0;
						_obj.small3Right = 0;
					}
				} else {
					// 以宽度为准
					_obj.largeWidth = (_containerWidth - this.gap * 2) / 3;
					_obj.largeHeight = (_obj.largeWidth * 9) / 16;
					_obj.largeLeft = 0;
					const _offset = (_containerHeight - 2 * _obj.largeHeight - this.gap) / 2;

					_obj.small1Height = _obj.largeHeight;
					_obj.small1Width = _obj.largeWidth;
					_obj.small1Right = _obj.largeWidth * 2 + this.gap * 2;

					_obj.small2Height = _obj.largeHeight;
					_obj.small2Width = _obj.largeWidth;
					_obj.small2Right = _obj.largeWidth + this.gap;

					_obj.small3Height = _obj.largeHeight;
					_obj.small3Width = _obj.largeWidth;
					_obj.small3Right = _obj.largeWidth + this.gap;

					_obj.small4Height = _obj.largeHeight;
					_obj.small4Width = _obj.largeWidth;
					_obj.small4Right = 0;

					_obj.small5Height = _obj.largeHeight;
					_obj.small5Width = _obj.largeWidth;
					_obj.small5Right = 0;

					if (!this.verticalAlign || this.verticalAlign === 'center') {
						// 居中对齐
						_obj.largeTop = _offset;
						_obj.small1Top = _offset + _obj.largeHeight + this.gap;
						_obj.small2Bottom = _offset + _obj.largeHeight + this.gap;
						_obj.small3Bottom = _offset;
						_obj.small4Bottom = _offset + _obj.largeHeight + this.gap;
						_obj.small5Bottom = _offset;
					} else if (this.verticalAlign === 'top') {
						// 顶部对齐
						_obj.largeTop = 0;
						_obj.small1Top = _obj.largeHeight + this.gap;
						_obj.small2Bottom = _offset * 2 + _obj.largeHeight + this.gap;
						_obj.small3Bottom = _offset * 2;
						_obj.small4Bottom = _offset * 2 + _obj.largeHeight + this.gap;
						_obj.small5Bottom = _offset * 2;
					} else {
						// 底部对齐
						_obj.largeTop = _offset * 2;
						_obj.small1Top = _offset * 2 + _obj.largeHeight + this.gap;
						_obj.small2Bottom = _obj.largeHeight + this.gap;
						_obj.small3Bottom = 0;
						_obj.small4Bottom = _obj.largeHeight + this.gap;
						_obj.small5Bottom = 0;
					}
				}
			}
		}
		return _obj;
	}

	// 初始化样式
	private initStyle(obj: PlayerSizeObj): void {
		let _styleStr = '';
		if (this.displayMode === 'pave') {
			_styleStr = `\
              .${CLASS_CONFIG.LARGE_CLASS} {\
                position: absolute;\
                left: ${obj.largeLeft}px;\
                top: ${obj.largeTop}px;\
                width: ${obj.largeWidth}px;\
                height: ${obj.largeHeight}px;\
                z-index: 1;\
                box-sizing: border-box;\
                ${this.borderStyle ? `border: ${this.borderStyle};` : ''}\
              }\
              .${CLASS_CONFIG.SMALL_CLASS_1} {\
                position: absolute;\
                right: ${obj.small1Right}px;\
                top: ${obj.small1Top}px; \
                width: ${obj.small1Width}px;\
                height: ${obj.small1Height}px;\
                z-index: 1;\
                box-sizing: border-box;\
                ${this.borderStyle ? `border: ${this.borderStyle};` : ''}\
              }\
              .${CLASS_CONFIG.SMALL_CLASS_2} {\
                position: absolute;\
                bottom: ${obj.small2Bottom}px;\
                right: ${obj.small2Right}px;\
                width: ${obj.small2Width}px;\
                height: ${obj.small2Height}px;\
                z-index: 1;\
                box-sizing: border-box;\
                ${this.borderStyle ? `border: ${this.borderStyle};` : ''}\
              }\
              .${CLASS_CONFIG.SMALL_CLASS_3} {\
                position: absolute;\
                bottom: ${obj.small3Bottom}px;\
                right: ${obj.small3Right}px;\
                width: ${obj.small3Width}px;\
                height: ${obj.small3Height}px;\
                z-index: 1;\
                box-sizing: border-box;\
                ${this.borderStyle ? `border: ${this.borderStyle};` : ''}\
              }\
              .${CLASS_CONFIG.SMALL_CLASS_4} {\
                position: absolute;\
                bottom: ${obj.small4Bottom}px;\
                right: ${obj.small4Right}px;\
                width: ${obj.small4Width}px;\
                height: ${obj.small4Height}px;\
                z-index: 1;\
                box-sizing: border-box;\
                ${this.borderStyle ? `border: ${this.borderStyle};` : ''}\
              }\
              .${CLASS_CONFIG.SMALL_CLASS_5} {\
                position: absolute;\
                bottom: ${obj.small5Bottom}px;\
                right: ${obj.small5Right}px;\
                width: ${obj.small5Width}px;\
                height: ${obj.small5Height}px;\
                z-index: 1;\
                box-sizing: border-box;\
                ${this.borderStyle ? `border: ${this.borderStyle};` : ''}\
              }\
              .${CLASS_CONFIG.SMALL_CLASS_1} .xgplayer-controls,
              .${CLASS_CONFIG.SMALL_CLASS_2} .xgplayer-controls,
              .${CLASS_CONFIG.SMALL_CLASS_3} .xgplayer-controls,
              .${CLASS_CONFIG.SMALL_CLASS_4} .xgplayer-controls,
              .${CLASS_CONFIG.SMALL_CLASS_5} .xgplayer-controls,
              .${CLASS_CONFIG.SMALL_CLASS_1} .xgplayer-replay,
              .${CLASS_CONFIG.SMALL_CLASS_2} .xgplayer-replay,
              .${CLASS_CONFIG.SMALL_CLASS_3} .xgplayer-replay,
              .${CLASS_CONFIG.SMALL_CLASS_4} .xgplayer-replay,
              .${CLASS_CONFIG.SMALL_CLASS_5} .xgplayer-replay,
              .${CLASS_CONFIG.SMALL_CLASS_1} .xgplayer-start,
              .${CLASS_CONFIG.SMALL_CLASS_2} .xgplayer-start, 
              .${CLASS_CONFIG.SMALL_CLASS_3} .xgplayer-start, 
              .${CLASS_CONFIG.SMALL_CLASS_4} .xgplayer-start, 
              .${CLASS_CONFIG.SMALL_CLASS_5} .xgplayer-start {\
								display: none !important;\
              }\
              .${CLASS_CONFIG.VIDEO_ERROR} {\
								position: absolute;\
								top: 0;\
								left: 0;\
								z-index: 126;\
								display: flex;\
								justify-content: center;\
								align-items: center;\
                width: 100%;\
                height: 100%;\
                background: #000;\
                font-size: 14px;\
								font-family: 'Alibaba PuHuiTi';\
								color: #fff;\
                cursor: default;\
              }\
							.${CLASS_CONFIG.VIDEO_IS_FINISH}::after {\
								content: '${this.endTips}';\
								position: absolute;\
								top: 0;\
								left: 0;\
								z-index: 126;\
								display: flex;\
								justify-content: center;\
								align-items: center;\
                width: 100%;\
                height: 100%;\
                background: #000;\
                font-size: 14px;\
								font-family: 'Alibaba PuHuiTi';\
								color: #fff;\
                cursor: default;\
              }\
              ${
								this.commonStyle && this.commonStyle.playbackRateColor
									? `.xgplayer .xg-options-list li:hover, 
              .xgplayer .xg-options-list li.selected {
								color: ${this.commonStyle.playbackRateColor} !important;
              }`
									: ''
							}
            `;
		}
		let styleEl = document.getElementById(CLASS_CONFIG.MULTI_PLAYER_STYLE);
		if (!styleEl) {
			// 创建style标签
			styleEl = createDom('style', {
				id: CLASS_CONFIG.MULTI_PLAYER_STYLE,
				type: 'text/css'
			});
			if (styleEl) {
				styleEl.innerHTML = _styleStr;
				document.head.appendChild(styleEl);
			}
		} else {
			styleEl.innerHTML = _styleStr;
		}
	}

	// 创建dom
	private initDOM(): void {
		// 创建容器dom
		let _containerDom = hasDomByCSSSelector(this.el, `.${CLASS_CONFIG.MULTI_LAYER_WRAP}`);
		if (!_containerDom) {
			_containerDom = createDom(
				'div',
				{
					class: CLASS_CONFIG.MULTI_LAYER_WRAP
				},
				{
					position: 'relative',
					width: `${this.containerWidth}px`,
					height: `${this.containerHeight}px`
				}
			);
			if (_containerDom) {
				this.el.appendChild(_containerDom);
			}
		}
		// 创建player dom
		if (_containerDom) {
			this.urlList.forEach((item) => {
				// 检查player dom是否存在
				const _dom = hasDomByCSSSelector(_containerDom, `#video_${item.id}`);
				if (!_dom) {
					// 找到可用的className
					const _classItem = this.classList.find((i) => !i.usedId);
					if (_classItem) {
						const _styleObj: { border?: string } = {};
						if (item.borderStyle) {
							_styleObj.border = item.borderStyle;
						}
						const _newDom = createDom(
							'div',
							{
								class: `${_classItem.className} ${CLASS_CONFIG.MULTI_LAYER}`,
								id: `video_${item.id}`
							},
							_styleObj
						);
						if (_newDom) {
							_containerDom.appendChild(_newDom);
							// 设置该className已使用
							_classItem.usedId = item.id;
							// 创建player dom
							const _playerDom = createDom(
								'div',
								{
									class: CLASS_CONFIG.VIDEO_WRAP
								},
								{
									width: '100%',
									height: '100%'
								}
							);
							if (_playerDom) {
								_newDom.appendChild(_playerDom);
								let _player: Player | null = null;
								if (item.placeholder || !item.url) {
									// 设置播放器为错误样式
									_playerDom.classList.add(CLASS_CONFIG.VIDEO_ERROR);
									if (
										item.placeholder &&
										/\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(item.placeholder)
									) {
										// 设置图片占位
										setDOMStyle(_playerDom, {
											background: `url(${item.placeholder}) no-repeat center`,
											backgroundSize: '100% 100%'
										});
									} else {
										// 设置文字占位
										_playerDom.innerText = item.placeholder || DEFAULT_CONFIG.placeholder;
									}
								} else {
									// 创建播放器
									_player = this.initPlayer(item, _playerDom);
								}
								// 初始化播放器配置
								this.initPlayerSetting(_player, item, _playerDom);
							}
						}
					}
				} else {
					// 已经存在播放器，直接初始化播放器配置
					this.initPlayerSetting(
						this.playerList.find((i) => i.id === item.id)?.player,
						item,
						_dom.querySelector(`.${CLASS_CONFIG.VIDEO_WRAP}`) as HTMLElement
					);
					// 对于已存在的播放器，重新设置播放器的配置，如borderStyle、progressDot等
					this.resetPlayerConfig(
						this.playerList.find((i) => i.id === item.id),
						_dom
					);
				}
			});
		}
	}

	// 创建播放器
	private initPlayer(obj: UrlListOptionsRequireOne, dom: HTMLElement): Player | null {
		// 判断是否是主画面
		const _classItem = this.classList.find((item) => item.usedId === obj.id);
		const _playerItem = this.playerList.find((item) => item.id === obj.id);
		if (_playerItem && _classItem) {
			// 设置主画面
			_playerItem.isLarge = _classItem.isLarge;
		}

		// 保存打点信息
		const _progressDot = _playerItem?.progressDot || this.progressDot;

		// 获取主画面的播放/暂停情况
		const _largeItem = this.playerList.find((item) => item.isLarge);

		const _playerObj: PlayerOptions = {
			el: dom,
			url: obj.url as string,
			autoplay: this.isFirst
				? this.autoplay
				: _largeItem && _largeItem.player
				? !_largeItem.player.paused
				: true, // 初次渲染时使用传入的自动播放属性，后续修改信源渲染时根据主画面的播放情况判断是否自动播放
			width: '100%',
			height: '100%',
			volume: {
				default:
					(this.hasVol && obj.hasVol) || (!this.hasVol && _playerItem?.isLarge)
						? DEFAULT_CONFIG.volume
						: 0, // 默认音量
				miniVolume: DEFAULT_CONFIG.miniVolume // 静音恢复的最小音量
			},
			isLive: this.isLive,
			playsinline: true,
			closeVideoClick: true,
			startTime: obj.currentTime || this.currentTime || 0,
			progressDot: _progressDot,
			commonStyle: this.commonStyle // 公共样式
		};

		if (this.type === 'flv' && FlvPlugin.isSupported()) {
			// 使用flv插件
			_playerObj.plugins = [FlvPlugin];
			if (typeof this.preloadTime === 'number') {
				_playerObj.preloadTime = this.preloadTime;
			}
		} else if (
			this.type === 'hls' &&
			!document.createElement('video').canPlayType('application/vnd.apple.mpegurl') &&
			HlsPlugin.isSupported()
		) {
			// 使用hls插件
			_playerObj.plugins = [HlsPlugin];
			if (typeof this.preloadTime === 'number') {
				_playerObj.preloadTime = this.preloadTime;
			}
		} else if (
			(this.type === 'flv' && !FlvPlugin.isSupported()) ||
			(this.type === 'hls' &&
				!document.createElement('video').canPlayType('application/vnd.apple.mpegurl') &&
				!HlsPlugin.isSupported())
		) {
			// 环境不支持播放
			dom.classList.add(CLASS_CONFIG.VIDEO_ERROR);
			dom.innerText = DEFAULT_CONFIG.noSupport;
			return null;
		}
		// 创建播放器
		return new Player(_playerObj);
	}

	// 初始化播放器配置
	private initPlayerSetting(
		player: Player | null | undefined,
		obj: UrlListOptionsRequireOne,
		dom: HTMLElement
	): void {
		// 保存player对象信息
		const _playerItem = this.playerList.find((item) => item.id === obj.id);
		const _classItem = this.classList.find((item) => item.usedId === obj.id);
		if (_playerItem) {
			if (player) {
				_playerItem.player = player;
			}
			if (_classItem) {
				// 设置主画面
				_playerItem.isLarge = _classItem.isLarge;
			}
			// 保存容器dom（video-wrap）
			_playerItem.root = dom;
		}
		if (player && _playerItem) {
			// 播放结束事件
			if (_playerItem._endedEvent) {
				player.off(Events.ENDED, _playerItem._endedEvent);
			}
			_playerItem._endedEvent = (): void => {
				console.log('播放结束');
				// 如果是小画面，暂停并显示已完成状态
				if (!this.isLive && _playerItem && !_playerItem.isLarge) {
					player.pause();
					dom.classList.add(CLASS_CONFIG.VIDEO_IS_FINISH);
				}
			};
			player.on(Events.ENDED, _playerItem?._endedEvent);

			// 播放错误事件
			if (_playerItem._errorEvent) {
				player.off(Events.ERROR, _playerItem._errorEvent);
			}
			_playerItem._errorEvent = (err): void => {
				console.log('播放错误', err);
				// 5102网络波动错误
				if (
					player &&
					!dom.className.includes(CLASS_CONFIG.VIDEO_IS_FINISH) &&
					err.errorCode === 5102
				) {
					player.destroy();
					// 重新创建播放器
					const _player = this.initPlayer(obj, dom);
					this.initPlayerSetting(_player, obj, dom);
					// 绑定播放器事件
					(this as any).playerEventBind();
					// 设置音量记忆
					if (this.enableVolumeMemory) {
						(this as any).setVolumeMemory();
					}
				}
			};
			player.on(Events.ERROR, _playerItem._errorEvent);

			// 音量变化事件
			if (_playerItem._volumeChangeEvent) {
				player.off(Events.VOLUME_CHANGE, _playerItem._volumeChangeEvent);
			}
			_playerItem._volumeChangeEvent = (): void => {
				if (player.volume) {
					this.playerList.forEach((item) => {
						if (item.id !== obj.id && item.player) {
							item.player.volume = 0;
						}
					});
				}
			};
			player.on(Events.VOLUME_CHANGE, _playerItem._volumeChangeEvent);

			// 倍速变化事件
			if (_playerItem._rateChangeEvent) {
				player.off(Events.RATE_CHANGE, _playerItem._rateChangeEvent);
			}
			_playerItem._rateChangeEvent = (): void => {
				if (player.playbackRate) {
					this.playerList.forEach((item) => {
						if (item.id !== obj.id && item.player) {
							item.player.playbackRate = player.playbackRate;
						}
					});
				}
			};
			player.on(Events.RATE_CHANGE, _playerItem._rateChangeEvent);

			// 播放器准备完成事件
			if (_playerItem._readyEvent) {
				player.off(Events.READY, _playerItem._readyEvent);
			}
			_playerItem._readyEvent = (): void => {
				// 设置水印
				if (this.watermarkText) {
					setWaterMark(dom, this.watermarkText);
				}
			};
			player.on(Events.READY, _playerItem._readyEvent);

			// 播放器可以流畅播放事件，只有初次渲染时才绑定，后续修改信源时不绑定
			if (this.isFirst) {
				let _isFirst = true;
				if (_playerItem._canplayEvent2) {
					player.off(Events.CANPLAY, _playerItem._canplayEvent2);
				}
				_playerItem._canplayEvent2 = (): void => {
					// 只有第一次渲染时触发下面的逻辑
					if (_isFirst) {
						_isFirst = false;
						// 初始化时由于浏览器播放限制出现暂停的画面，则其他画面也要跟着暂停
						const _hasPaused = this.playerList.find(
							(item) => item.player?.paused && !item.placeholder
						);
						// state = 2 当前播放位置的数据可用，但不足以播放下一帧
						// state = 3 当前播放位置以及未来至少一小段时间的数据是可用的（至少有两帧以上的数据）
						// state = 4 有足够的数据可用，并且下载速率足够，媒体可以不间断地播放到最后
						if (
							_hasPaused &&
							(_hasPaused?.player?.readyState === 2 ||
								_hasPaused?.player?.readyState === 3 ||
								_hasPaused?.player?.readyState === 4)
						) {
							player.pause();
						}
					}
				};
				player.on(Events.CANPLAY, _playerItem._canplayEvent2);
			}

			// 播放器自动播放失败事件 当某个画面自动播放失败时，其他画面全部暂停
			if (_playerItem._autoplaypreventedEvent) {
				player.off(Events.AUTOPLAY_PREVENTED, _playerItem._autoplaypreventedEvent);
			}
			_playerItem._autoplaypreventedEvent = (): void => {
				console.log('自动播放失败');
				this.playerList.forEach((item) => {
					item.player?.pause();
				});
			};
			player.on(Events.AUTOPLAY_PREVENTED, _playerItem._autoplaypreventedEvent);

			// 播放时间改变事件
			// 对于新创建的播放器，如果这时已经设置了心跳，就定义心跳的回调
			if (
				(this as any).alreadySetHeartbeatTime &&
				(this as any).heartbeatTime &&
				(this as any).heartbeatCallback
			) {
				(this as any).setHeartbeatTime(
					{ heartbeatTime: (this as any).heartbeatTime },
					(this as any).heartbeatCallback
				);
			}
			if (_playerItem._timeupdateEvent) {
				player.off(Events.TIME_UPDATE, _playerItem._timeupdateEvent);
			}
			_playerItem._timeupdateEvent = (): void => {
				if (_playerItem.id === (this as any).heartbeatId && _playerItem._timeupdateCallback) {
					// 如果是主画面，调用播放时间改变的回调
					_playerItem._timeupdateCallback();
				}
			};
			player.on(Events.TIME_UPDATE, _playerItem?._timeupdateEvent);

			// 点击视频进度条的回调
			if (_playerItem._seekingEvent) {
				player.off(Events.SEEKING, _playerItem._seekingEvent);
			}
			_playerItem._seekingEvent = (): void => {
				// 秒转毫秒
				const currentTime = parseInt(String(player.currentTime * 1000), 0);
				if (this.seekingCallback) {
					this.seekingCallback(_playerItem.id, currentTime);
				}
			};
			player.on(Events.SEEKING, _playerItem?._seekingEvent);
		}
	}

	// 重新设置播放器的配置
	private resetPlayerConfig(playerItem: PlayerListOptions | undefined, dom: HTMLElement): void {
		if (playerItem) {
			// 设置边框样式
			if (playerItem.borderStyle) {
				setDOMStyle(dom, {
					border: playerItem.borderStyle
				});
			}
			// 设置占位文字
			if (playerItem.placeholder) {
				// 销毁播放器
				playerItem.player?.destroy();
				// 清除dom
				const _playerDom: HTMLElement | null = dom.querySelector(`.${CLASS_CONFIG.VIDEO_WRAP}`);
				if (_playerDom) {
					_playerDom.innerHTML = '';
					// 设置播放器为错误样式
					_playerDom.classList.add(CLASS_CONFIG.VIDEO_ERROR);
					if (/\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(playerItem.placeholder)) {
						// 设置图片占位
						setDOMStyle(_playerDom, {
							background: `url(${playerItem.placeholder}) no-repeat center`,
							backgroundSize: '100% 100%'
						});
					} else {
						// 设置文字占位
						_playerDom.innerText = playerItem.placeholder || DEFAULT_CONFIG.placeholder;
					}
				}
				// 如果该画面是主画面，则停止同步定时器
				if (playerItem.isLarge && (this as any).syncInterval) {
					// 停止同步
					clearInterval((this as any).syncInterval);
					(this as any).syncInterval = null;
				}
			}
			// 设置播放进度
			if (playerItem.player && (playerItem.currentTime || playerItem.currentTime === 0)) {
				playerItem.player.currentTime = playerItem.currentTime;
			}
		}
	}
}

export default APIMixin(FunctionMixin(MultiPlayer));
